package com.cn.sqlSession;

import com.cn.pojo.Configuration;
import com.cn.pojo.MapperdStatement;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
        this.executor = new SimpleExecutor(configuration);
    }

    @Override
    public <E> List<E> selectList(String statementId, Object... param) throws Exception {
        MapperdStatement mapperdStatement = configuration.getStatementMap().get(statementId);

        List<Object> list = executor.query(mapperdStatement, param);

        return (List<E>) list;
    }

    @Override
    public <T> T selectOne(String statementId, Object... param) throws Exception {
        List<Object> objects = selectList(statementId, param);
        if (objects.size() == 1){
            return (T) objects.get(0);
        } else if (objects.size() > 1) {
            throw new RuntimeException("select by one");
        }
        return null;
    }

    @Override
    public Integer updateById(String statementId, Object... param) throws Exception {
        MapperdStatement mapperdStatement = configuration.getStatementMap().get(statementId);
        int count = executor.update(mapperdStatement, param);
        return count;
    }

    @Override
    public Integer add(String statementId, Object... param) throws Exception {
        MapperdStatement mapperdStatement = configuration.getStatementMap().get(statementId);
        Integer count = executor.insert(mapperdStatement, param);
        return count;
    }

    @Override
    public Integer delById(String statementId, Object... param) throws Exception {
        MapperdStatement mapperdStatement = configuration.getStatementMap().get(statementId);
        Integer count = executor.delete(mapperdStatement, param);
        return count;
    }


    @Override
    public <T> T getMapper(Class<?> mapperClass) {

        return (T) new MapperProxy().newInstance(this,  mapperClass, configuration);

    }
    /*@Override
    public <T> T getMapper(Class<?> mapperClass) {
        // mapperClass : 接口名称

        // 动态代理对象
        //  参数： this.getClass().getClassLoader() 类加载器
        //          new Class[]{mapperClass}  需要生成的代理对象
        //           InvocationHandler     回调方法
        Object proxyInstance = Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperClass},
                new InvocationHandler() {
            @Override
            //proxy   代理对象
            //method  执行的方法
            //args    参数
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 组建 statementId
                // 要求： namespace.id 要与 mapper接口的全限定名.方法名相同
                String methodName = method.getName();

                String className = method.getDeclaringClass().getName();
                String statementId = className + "." + methodName;

                // 返回类型 是否包含泛型： 是，返回类型为集合。 不是，返回类型为对象
                if (method.getGenericReturnType() instanceof ParameterizedType){
                    return selectList(statementId, args);
                }

                return selectOne(statementId, args);
            }
        });

        return (T) proxyInstance;
    }*/
}
